package com.dofun.locationservice.service;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Message;

import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.map.MyLocationData;
import com.baidu.mapapi.model.LatLng;
import com.dofun.locationservice.MsgObservable;
import com.dofun.locationservice.bean.Information;
import com.dofun.locationservice.core.MyApplication;
import com.dofun.locationservice.listener.MyLocationListener;
import com.dofun.locationservice.util.L;
import com.dofun.locationservice.util.ThreadPoolUtils;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;

import static com.dofun.locationservice.RunConstants.FIRST_LOCATION_MSG;
import static com.dofun.locationservice.RunConstants.RUN_FIRST_LOCATION_MSG;
import static com.dofun.locationservice.RunConstants.RUN_LOCATION_MSG;

/**
 * Created by G on 2019/9/10.
 */

public class WorkService extends Service {

    static final int HASH_CODE = 1;

    //是否 任务完成, 不再需要服务运行?
    public static boolean isShouldStopService = false;
    public static boolean isRunStop = true;
//    public static boolean isRunStop = false;

    public static Disposable sSubscription;
    private LocationClient mLocationClient;

    private WorkSerPresenter mSerPersenter;

    @Override
    public void onCreate() {
        super.onCreate();
        mSerPersenter = new WorkSerPresenter();
    }

    /**
     * 1.防止重复启动，可以任意调用startService(Intent i);
     * 2.利用漏洞启动前台服务而不显示通知;
     * 3.在子线程中运行定时任务，处理了运行前检查和销毁时保存的问题;
     * 4.启动守护服务;
     * 5.守护 Service 组件的启用状态, 使其不被 MAT 等工具禁用.
     */
    int onStart(Intent intent, int flags, int startId) {
        startForeground(HASH_CODE, new Notification());
        //----------业务逻辑----------

        //实际使用时，根据需求，将这里更改为自定义的条件，判定服务应当启动还是停止 (任务是否需要运行)
        if (isShouldStopService) stopService();
        else startService();

        //----------业务逻辑----------
        return START_STICKY;
    }

    // 设置位置监听。从startCommand调用。
    @SuppressLint("MissingPermission")
    private void setLocationListener() {

        //通过LocationClientOption设置LocationClient相关参数
        LocationClientOption option = new LocationClientOption();
        //可选，设置定位模式，默认高精度
        //LocationMode.Hight_Accuracy：高精度；
        //LocationMode. Battery_Saving：低功耗；
        //LocationMode. Device_Sensors：仅使用设备；
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //使用高精度和仅用设备两种定位模式的，参数必须设置为true
        option.setCoorType("bd09ll"); // 设置坐标类型
        option.setScanSpan(1000);
        option.setOpenGps(true); // 设置是否使用gps，默认false
//        option.setLocationNotify(true);// 设置是否当GPS有效时按照1S/1次频率输出GPS结果，默认false
        option.SetIgnoreCacheException(true); // 设置是否收集Crash信息，默认收集，即参数为false
        option.setWifiCacheTimeOut(5*60*1000);

        //定位初始化
        mLocationClient = new LocationClient(this);
        //设置locationClientOption
        mLocationClient.setLocOption(option);
        //注册LocationListener监听器
        mLocationClient.registerLocationListener(locationGpsListener);
        //开启地图定位图层
        mLocationClient.start();

    }

    void startService() {
        //检查服务是否不需要运行
        if (isShouldStopService) return;
        //若还没有取消订阅，说明任务仍在运行，为防止重复启动，直接 return
        if (sSubscription != null && !sSubscription.isDisposed()) return;

        //----------业务逻辑----------

        // 注册地理位置的监听.
        setLocationListener();

        System.out.println("检查磁盘中是否有上次销毁时保存的数据");
        sSubscription = Observable
                .interval(3, TimeUnit.SECONDS)
                //取消任务时取消定时唤醒
                .doOnDispose(() -> {
                    System.out.println("保存数据到磁盘。");
                }).subscribe(count -> {
//                    System.out.println("每 3 秒采集一次数据... count = " + count);
                });

        //----------业务逻辑----------
    }

    /**
     * 停止服务并取消定时唤醒
     * <p>
     * 停止服务使用取消订阅的方式实现，而不是调用 Context.stopService(Intent name)。因为：
     * 1.stopService 会调用 Service.onDestroy()，而 WorkService 做了保活处理，会把 Service 再拉起来；
     * 2.我们希望 WorkService 起到一个类似于控制台的角色，即 WorkService 始终运行 (无论任务是否需要运行)，
     * 而是通过 onStart() 里自定义的条件，来决定服务是否应当启动或停止。
     */
    public static void stopService() {
        //我们现在不再需要服务运行了, 将标志位置为 true
        isShouldStopService = true;
        //取消对任务的订阅
        if (sSubscription != null) sSubscription.dispose();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return onStart(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        onStart(intent, 0, 0);
        return null;
    }

    void onEnd(Intent rootIntent) {
        System.out.println("保存数据到磁盘。");
        startService(new Intent(MyApplication.getInstance(), WorkService.class));
    }

    /**
     * 最近任务列表中划掉卡片时回调
     */
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        onEnd(rootIntent);
    }

    /**
     * 设置-正在运行中停止服务时回调
     */
    @Override
    public void onDestroy() {
        onEnd(null);
    }

    public static MyLocationData preLocation;
    private static ArrayList<LatLng> mLocationList = new ArrayList<>();

    /**
     * location的监听。
     */
    private MyLocationListener locationGpsListener = new MyLocationListener() {

        @Override
        public void onLocationData(MyLocationData locationData) {
            if (!isRunStop) {
                ThreadPoolUtils.getInstance().addTask(() -> {
                    LatLng latLng = new LatLng(locationData.latitude, locationData.longitude);

                    if (preLocation != null) {
                        // 如果位置和上一次记录的位置点相同，则认为没有移动。
                        if (preLocation.latitude != locationData.latitude
                                || preLocation.longitude != locationData.longitude) {

                            // 将变动的点存入集合中
                            // 如果locationList
                            // 集合的数量大于startTimes，则说明这段开始已经有记录的点。
                            mLocationList.add(latLng);

                            Information info =
                                    new Information(Information.GET_ONCE_LOCATION,
                                            mLocationList, locationData);
                            Message msg = Message.obtain();
                            msg.what = RUN_LOCATION_MSG;
                            msg.obj = info;
                            MsgObservable.getInstance().sendMsgs(msg);
                        }
                    } else {
                        mLocationList.add(latLng);

                        Message msg = Message.obtain();
                        msg.what = RUN_FIRST_LOCATION_MSG;
                        msg.obj = locationData;
                        MsgObservable.getInstance().sendMsgs(msg);
                    }
                    preLocation = locationData;
                });
            } else {
                L.i("位置改变了一次，暂停状态未记录！");
                preLocation = null;
                if (mLocationList.size() > 0) {
                    mLocationList.clear();
                }
                Message msg = Message.obtain();
                msg.what = FIRST_LOCATION_MSG;
                msg.obj = locationData;
                MsgObservable.getInstance().sendMsgs(msg);
            }
        }

    };
}
